package multicast

import (
	"context"
	"time"

	"github.com/brocaar/chirpstack-api/go/v3/gw"
	"github.com/jmoiron/sqlx"
	"github.com/pkg/errors"
	"network/v3/internal/config"
	"network/v3/internal/storage"
)

var (
	errAbort       = errors.New("")
	ErrInvalidFCnt = errors.New("invalid frame-counter value")

	multicastGatewayDelay time.Duration
	schedulerInterval     time.Duration
	installationMargin    float64
	downlinkTXPower       int

	// TODO: make configurable
	classBEnqueueMargin = time.Second * 5
)

type multicastContext struct {
	ctx context.Context

	DownlinkFrame      gw.DownlinkFrame
	DB                 sqlx.Ext
	MulticastGroup     storage.MulticastGroup
	MulticastQueueItem storage.MulticastQueueItem
	DownlinkGateway    storage.DeviceGatewayRXInfo
}

// Setup sets up the multicast package.
func Setup(conf config.Config) error {
	nwServer := conf.NetworkServer
	multicastGatewayDelay = nwServer.Scheduler.ClassC.MulticastGatewayDelay
	schedulerInterval = nwServer.Scheduler.SchedulerInterval
	installationMargin = nwServer.NetworkSettings.InstallationMargin
	downlinkTXPower = nwServer.NetworkSettings.DownlinkTXPower

	return nil
}

// HandleScheduleQueueItem handles the scheduling of the given queue-item.
func HandleScheduleQueueItem(ctx context.Context, db sqlx.Ext, qi storage.MulticastQueueItem) error {
	mctx := multicastContext{
		ctx:                ctx,
		DB:                 db,
		MulticastQueueItem: qi,
		DownlinkFrame: gw.DownlinkFrame{
			Items: make([]*gw.DownlinkFrameItem, 1),
		},
	}

	return HandleScheduleQueueItemRunTasks(&mctx)
}

func HandleScheduleQueueItemRunTasks(mctx *multicastContext) error {
	for _, task := range multicastTasks {
		if err := task(mctx); err != nil {
			if err == errAbort {
				return nil
			}
			return err
		}
	}

	return nil
}
